package com.smh;

import org.junit.jupiter.api.Test;

import java.util.Iterator;
import java.util.function.Consumer;

/**
 * @author shiminghui
 * @date 2025/1/30 14:41
 * @description: TODO
 */
public class _005单项链表_哨兵 {
    @Test
    public void test001() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.loop(System.out::println);
    }

    @Test
    public void test002() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        for (Integer i : singleLinkedList) {
            System.out.println(i);
        }
    }

    @Test
    public void test003() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        System.out.println(singleLinkedList.get(0));
    }

    @Test
    public void test004() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.add(0, 4);
        for (Integer i : singleLinkedList) {
            System.out.println(i);
        }
    }

    @Test
    public void test005() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.add(0, 4);
        singleLinkedList.removeFirst();
        singleLinkedList.removeLast();
        for (Integer i : singleLinkedList) {
            System.out.println(i);
        }
    }

    @Test
    public void test006() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.add(0, 4);
        singleLinkedList.remove(3);
        for (Integer i : singleLinkedList) {
            System.out.println(i);
        }
    }

    @Test
    public void test007() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.add(0, 4);
        int i = singleLinkedList.get(0);
        System.out.println(i);
    }

    @Test
    public void test008() {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.loop2();
    }

    private class SingleLinkedList implements Iterable<Integer> {
        private Node head = new Node(0);

        public void addFirst(int data) {
            head.next = new Node(data, head.next);
        }

        public void addLast(int data) {
            Node last = findLast();
            last.next = new Node(data);
        }

        private Node findNode(int index) {
            if (index < -1) {
                return null;
            }
            int i = -1;
            for (Node indexNode = head; indexNode != null; indexNode = indexNode.next, i++) {
                if (i == index) {
                    return indexNode;
                }
            }
            return null;
        }

        public int get(int index) {
            Node node = findNode(index);
            if (node == null) {
                throw new IllegalArgumentException("index is illegal");
            } else {
                return node.data;
            }
        }

        public void add(int index, int data) {
            Node node = findNode(index - 1);
            if (node == null) {
                throw new IllegalArgumentException("index is illegal");
            } else {
                node.next = new Node(data, node.next);
            }
        }

        public int removeFirst() {
            if (head.next == null) {
                throw new IllegalArgumentException("index is illegal");
            }
            Node firstNode = head.next;
            int data = firstNode.data;
            head.next = firstNode.next;
            return data;
        }

        public int removeLast() {
            if (head.next == null) {
                throw new IllegalArgumentException("index is illegal");
            }

            Node indexNode = head.next;
            while (indexNode.next != null && indexNode.next.next != null) {
                indexNode = indexNode.next;
            }
            int data = indexNode.next.data;
            indexNode.next = null;
            return data;
        }

        public int remove(int index) {
            if (index == 0) {
                return removeFirst();
            }

            Node node = findNode(index - 1);
            if (node == null || node.next == null) {
                throw new IllegalArgumentException("index is illegal");
            }

            int data = node.next.data;
            node.next = node.next.next;
            return data;
        }

        public Node findLast() {
            Node indexNode = head;
            while (indexNode.next != null) {
                indexNode = indexNode.next;
            }
            return indexNode;
        }

        public void loop(Consumer<Integer> consumer) {
            Node indexNode = head.next;
            while (indexNode != null) {
                consumer.accept(indexNode.data);
                indexNode = indexNode.next;
            }
        }

        public void loop2() {
            recursion(head.next);
        }

        private void recursion(Node node) {
            System.out.println(node.data);
            if (node.next != null) {
                recursion(node.next);
            }
        }

        @Override
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                private Node indexNode = head.next;

                @Override
                public boolean hasNext() {
                    if (indexNode == null) {
                        return false;
                    }
                    return true;
                }

                @Override
                public Integer next() {
                    int data = indexNode.data;
                    indexNode = indexNode.next;
                    return data;
                }
            };
        }


        private static class Node {
            private int data;
            private Node next;

            public Node(int data) {
                this.data = data;
                this.next = null;
            }

            public Node(int data, Node next) {
                this.data = data;
                this.next = next;
            }
        }
    }
}
